#pragma once

#include "Vectors.h"

#include <iostream>
#include <fstream>
#include <string>
#include <cassert>
#include <vector>

class ZStream
{
public:

	ZStream() : m_openTag(0) {}
	~ZStream()
	{
		Flush();
		Close();
	}

	bool Open(const char* const i_file, std::ios_base::open_mode i_openMode)
	{
		m_stream.open(i_file, i_openMode);
		return m_stream.is_open();
	}

	void Close()
	{
		m_stream.close();
	}

	void Flush()
	{
		m_stream.flush();
	}

	bool IsEnd()
	{
		return m_stream.eof();
	}

	void WriteOpenTag(const char*const i_tag)
	{
		for(size_t i = 0; i < m_openTag; ++i)
			m_stream << "\t" ;

		m_stream << "[" << i_tag << "]\n";

		++m_openTag;
	}

	void WriteCloseTag(const char*const i_tag)
	{
		--m_openTag;

		for(size_t i = 0; i < m_openTag; ++i)
			m_stream << "\t" ;

		m_stream << "[/" << i_tag << "]\n";

	}

	template<typename T>
	void WriteAttribute(const char*const i_tag, const T& i_object)
	{
		for(size_t i = 0; i < m_openTag; ++i)
			m_stream << "\t" ;
		
		m_stream << i_tag << "=" << i_object << "\n";
	}

	// best match for std::vector<std::pair<int,int> >
	void WriteAttribute(const char*const i_tag, const std::vector<std::pair<int,int> >& i_object)
	{
		for(size_t i = 0; i < m_openTag; ++i)
			m_stream << "\t" ;
		
		m_stream << i_tag << "=" << i_object.size() << " ";
		
		for(size_t i = 0; i < i_object.size(); ++i)
			m_stream << i_object[i].first << " " << i_object[i].second << " ";

		m_stream << "\n";
	}

	void WriteAttribute(const char*const i_tag, const IntVec& i_object)
	{
		for(size_t i = 0; i < m_openTag; ++i)
			m_stream << "\t" ;
		
		m_stream << i_tag << "=" << i_object.size() << " ";
		
		for(size_t i = 0; i < i_object.size(); ++i)
			m_stream << i_object[i] << " ";

		m_stream << "\n";
	}

	inline bool SkipLine()
	{
		//char buffer[64];
		//m_stream.getline(buffer, 64);
		return (GoTo('\n', 256) != 0);
	}

	template<typename T>
	void ReadAttribute(T& i_object)
	{
		//char buffer[64];
		//m_stream.getline(buffer, 64, '=');
		GoTo('=', 256);
		m_stream >> i_object;
	}

	void ReadAttribute(IntVec& i_object)
	{
		//char buffer[64];
		//m_stream.getline(buffer, 64, '=');
		GoTo('=', 256);
		size_t vectorSize = 0;

		m_stream >> vectorSize;

		for(size_t i = 0; i < vectorSize; ++i)
		{
			int val = 0;
			m_stream >> val;
			i_object.push_back(val);
		}
	}

	void ReadAttribute(std::vector<std::pair<int,int> >& i_object)
	{
		GoTo('=', 256);
		
		size_t vectorSize = 0;

		m_stream >> vectorSize;

		for(size_t i = 0; i < vectorSize; ++i)
		{
			std::pair<int, int> val;
			m_stream >> val.first;
			m_stream >> val.second;
			i_object.push_back(val);
		}
	}

	void ReadAttribute(std::string& i_object)
	{
		GoTo('=', 256);
		char buffer[64];
		m_stream.getline(buffer, 64);
		i_object = buffer;
	}

	size_t GoTo(const char i_delimit, const size_t i_maxChars)
	{
		char c;
		size_t counter = 1;
		
		do
		{
			c = static_cast<char>(m_stream.get());
		}
		while(counter++ <= i_maxChars && c != i_delimit );

		return counter;
	}

private:

	std::fstream	m_stream;
	size_t			m_openTag;
};